package net.hserver.gateway.core;

import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.handler.codec.http.*;
import net.hserver.gateway.core.bean.Proxy;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;

/**
 * @author hxm
 */
public class FrontendHandler extends ChannelInboundHandlerAdapter {

  public Channel outboundChannel;

  static void closeOnFlush(Channel ch) {
    if (ch.isActive()) {
      ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
    }
  }

  public void read(Proxy proxy, Object msg) {
    if (msg instanceof FullHttpRequest) {
      FullHttpRequest fullHttpRequest = (FullHttpRequest) msg;
      HttpHeaders headers = fullHttpRequest.headers();
      headers.set("Host", proxy.getServerNode().getInetSocketAddress().getHostString());
      outboundChannel.writeAndFlush(msg);
    } else {
      closeOnFlush(proxy.getCtx().channel());
    }
  }

  @Override
  public void channelRead(final ChannelHandlerContext ctx, Object msg) {
    Proxy proxy = new Proxy();
    Executor executor = ctx.executor();
    CompletableFuture<Proxy> proxyCompletableFuture = CompletableFuture.completedFuture(proxy);
    proxyCompletableFuture.thenApplyAsync(req -> ProxyHandler.builder(ctx, msg, proxy, this), executor)
            .thenApplyAsync(ProxyHandler::statistics, executor)
            .thenApplyAsync(ProxyHandler::filter, executor)
            .thenApplyAsync(ProxyHandler::proxyInfo, executor)
            .exceptionally(ProxyHandler::exception)
            .thenAcceptAsync(gateWayInfo -> ProxyHandler.endGateWay(proxyCompletableFuture, gateWayInfo, ctx, msg), ctx.channel().eventLoop());
  }

  @Override
  public void channelInactive(ChannelHandlerContext ctx) {
    if (outboundChannel != null) {
      closeOnFlush(outboundChannel);
    }
  }

  @Override
  public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
    cause.printStackTrace();
    closeOnFlush(ctx.channel());
  }
}
